/**
 * CipherSuites
 *
 * An enumeration of cipher-suites available for TLS to use, along with
 * their properties, and some convenience methods
 * Copyright (c) 2007 Henri Torgemane
 *
 * See LICENSE.txt for full license information.
 */
package com.hurlant.crypto.tls
{
	import com.hurlant.crypto.hash.MD5;
	import com.hurlant.crypto.hash.SHA1;

	public class CipherSuites
	{


		// only the lines marked "ok" are currently implemented.

		// rfc 2246

		public static const TLS_NULL_WITH_NULL_NULL:uint=0x0000; // ok
		public static const TLS_RSA_WITH_NULL_MD5:uint=0x0001; // ok
		public static const TLS_RSA_WITH_NULL_SHA:uint=0x0002; // ok
		public static const TLS_RSA_WITH_RC4_128_MD5:uint=0x0004; // ok
		public static const TLS_RSA_WITH_RC4_128_SHA:uint=0x0005; // ok
		public static const TLS_RSA_WITH_IDEA_CBC_SHA:uint=0x0007;
		public static const TLS_RSA_WITH_DES_CBC_SHA:uint=0x0009; // ok
		public static const TLS_RSA_WITH_3DES_EDE_CBC_SHA:uint=0x000A; // ok

		public static const TLS_DH_DSS_WITH_DES_CBC_SHA:uint=0x000C;
		public static const TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:uint=0x000D;
		public static const TLS_DH_RSA_WITH_DES_CBC_SHA:uint=0x000F;
		public static const TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:uint=0x0010;
		public static const TLS_DHE_DSS_WITH_DES_CBC_SHA:uint=0x0012;
		public static const TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:uint=0x0013;
		public static const TLS_DHE_RSA_WITH_DES_CBC_SHA:uint=0x0015;
		public static const TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:uint=0x0016;

		public static const TLS_DH_anon_WITH_RC4_128_MD5:uint=0x0018;
		public static const TLS_DH_anon_WITH_DES_CBC_SHA:uint=0x001A;
		public static const TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:uint=0x001B;

		// rfc3268

		public static const TLS_RSA_WITH_AES_128_CBC_SHA:uint=0x002F; // ok
		public static const TLS_DH_DSS_WITH_AES_128_CBC_SHA:uint=0x0030;
		public static const TLS_DH_RSA_WITH_AES_128_CBC_SHA:uint=0x0031;
		public static const TLS_DHE_DSS_WITH_AES_128_CBC_SHA:uint=0x0032;
		public static const TLS_DHE_RSA_WITH_AES_128_CBC_SHA:uint=0x0033;
		public static const TLS_DH_anon_WITH_AES_128_CBC_SHA:uint=0x0034;

		public static const TLS_RSA_WITH_AES_256_CBC_SHA:uint=0x0035; // ok
		public static const TLS_DH_DSS_WITH_AES_256_CBC_SHA:uint=0x0036;
		public static const TLS_DH_RSA_WITH_AES_256_CBC_SHA:uint=0x0037;
		public static const TLS_DHE_DSS_WITH_AES_256_CBC_SHA:uint=0x0038;
		public static const TLS_DHE_RSA_WITH_AES_256_CBC_SHA:uint=0x0039;
		public static const TLS_DH_anon_WITH_AES_256_CBC_SHA:uint=0x003A;

		private static var _props:Array;

		init();

		private static function init():void
		{
			_props=[];
			_props[TLS_NULL_WITH_NULL_NULL]=new CipherSuites(BulkCiphers.NULL, MACs.NULL, KeyExchanges.NULL);
			_props[TLS_RSA_WITH_NULL_MD5]=new CipherSuites(BulkCiphers.NULL, MACs.MD5, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_NULL_SHA]=new CipherSuites(BulkCiphers.NULL, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_RC4_128_MD5]=new CipherSuites(BulkCiphers.RC4_128, MACs.MD5, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_RC4_128_SHA]=new CipherSuites(BulkCiphers.RC4_128, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_DES_CBC_SHA]=new CipherSuites(BulkCiphers.DES_CBC, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_3DES_EDE_CBC_SHA]=new CipherSuites(BulkCiphers.DES3_EDE_CBC, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_AES_128_CBC_SHA]=new CipherSuites(BulkCiphers.AES_128, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_AES_256_CBC_SHA]=new CipherSuites(BulkCiphers.AES_256, MACs.SHA1, KeyExchanges.RSA);

			// ...
			// more later
		}

		private static function getProp(cipher:uint):CipherSuites
		{
			var p:CipherSuites=_props[cipher];
			if (p == null)
			{
				throw new Error("Unknown cipher " + cipher.toString(16));
			}
			return p;
		}

		public static function getBulkCipher(cipher:uint):uint
		{
			return getProp(cipher).cipher;
		}

		public static function getMac(cipher:uint):uint
		{
			return getProp(cipher).hash;
		}

		public static function getKeyExchange(cipher:uint):uint
		{
			return getProp(cipher).key;
		}

		public static function getDefaultSuites():Array
		{
			// a list of acceptable ciphers, sorted by preference.
			return [TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_RC4_128_MD5, TLS_RSA_WITH_DES_CBC_SHA];
		}

		public var cipher:uint;
		public var hash:uint;
		public var key:uint;

		public function CipherSuites(cipher:uint, hash:uint, key:uint)
		{
			this.cipher=cipher;
			this.hash=hash;
			this.key=key;
		}
	}
}


